package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.exception.BinaryException;
import com.binary.core.exception.MessageException;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.*;
import com.uinnova.product.eam.model.BootEntryBo;
import com.uinnova.product.eam.model.RoleAndBootEntryRoleBo;
import com.uinnova.product.eam.model.vo.BootEntryVo;
import com.uinnova.product.eam.service.BootEntrySvc;
import com.uinnova.product.eam.service.es.*;
import com.uino.bean.permission.base.SysModule;
import com.uino.bean.permission.base.SysRole;
import com.uino.bean.permission.base.SysRoleModuleRlt;
import com.uino.bean.permission.business.UserInfo;
import com.uino.bean.permission.query.CSysModule;
import com.uino.bean.permission.query.CSysRole;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.permission.ESRoleSvc;
import com.uino.dao.permission.rlt.ESRoleModuleRltSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.permission.microservice.IModuleSvc;
import com.uino.service.permission.microservice.impl.UserSvc;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BootEntrySvcImpl implements BootEntrySvc {

    @Autowired
    private BootEntryDao bootEntryDao;

    @Autowired
    private BootEntryFunctionDao bootEntryFunctionDao;

    @Autowired
    private BootPageProgressDao bootPageProgressDao;

    @Autowired
    private BootTrialPageProgressDao bootTrialPageProgressDao;
    @Autowired
    private UserSvc userSvc;
    @Autowired
    ESRoleModuleRltSvc rmRltSvc;
    @Autowired
    private BootEntryUserDao bootEntryUserDao;

    @Autowired
    private IModuleSvc svc;

    @Autowired
    private ESRoleSvc roleSvc;

    @Value("${http.resource.space}")
    private String httpResourceUrl;

    @Override
    public Long saveOrUpdateEntry(BootEntryBo bootEntryBo) {
        if (bootEntryBo.getId() == null) {
            Long result = checkAndSaveParameter(bootEntryBo);
            return result;
        }else{
            Long result = checkAndUpdateParameter(bootEntryBo);
            return result;
        }
    }

    @Override
    public List<BootEntryVo> getBootEntryList() {
        RoleAndBootEntryRoleBo roleAndBootEntryRoleBo = getUserRoleIds();
        if (roleAndBootEntryRoleBo == null) {
            return new ArrayList<>();
        }
        Set<Long> userRoleIds = roleAndBootEntryRoleBo.getUserRoleIds();
        if (userRoleIds == null || userRoleIds.size() < 1) {
            return new ArrayList<>();
        }
        if (getUserRoleIds().getBootEntryRoleIdSet() == null || roleAndBootEntryRoleBo.getBootEntryRoleIdSet().size() < 1) {
            return new ArrayList<>();
        }
        List<SysRoleModuleRlt> SysRoleModuleList= rmRltSvc.getListByRoleIds(userRoleIds);

        Set<Long> moduleId = SysRoleModuleList.stream().map(SysRoleModuleRlt::getModuleId).collect(Collectors.toSet());
        //查看存量可引导用户的信息
        BoolQueryBuilder queryCountBuilder = QueryBuilders.boolQuery();
        queryCountBuilder.must(QueryBuilders.termQuery("isFromStandard",true));
        queryCountBuilder.must(QueryBuilders.termsQuery("id",getUserRoleIds().getBootEntryRoleIdSet()));
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("sort").order(SortOrder.ASC));
        Page<BootEntryUserConfig> bootEntryUserConfigPage = bootEntryUserDao.getSortListByQuery(1, 2000, queryCountBuilder, "sort", true);
        List<BootEntryUserConfig> bootEntryUserList = bootEntryUserConfigPage.getData();
        if (bootEntryUserList == null || bootEntryUserList.size() < 1) {
            return new ArrayList<>();
        }
        //查看当前用户功能权限的引导项列表
        List<BootEntryVo> result = queryUserBootEntry(moduleId, bootEntryUserList);

        //处理资源链接
        if(result != null && result.size()>0){
            result.stream().forEach(entryVo->{
                if(entryVo != null ){
                    List<BootEntryConfig> bootEntryConfigList = entryVo.getBootEntryConfigList();
                    if(bootEntryConfigList !=null && bootEntryConfigList.size()>0){
                        bootEntryConfigList.stream().forEach(config->{
                            String resPath = config.getResourcePath();
                            if(resPath.startsWith("/rsm") || resPath.startsWith("rsm")){
                                resPath = resPath.replace("/rsm","").replace("rsm","");
                            }
                            config.setResourcePath(httpResourceUrl + resPath);
                        });
                    }
                }
            });
        }

        return result;
    }

    private List<BootEntryVo> queryUserBootEntry(Set<Long> moduleId, List<BootEntryUserConfig> bootEntryUserList) {
        List<BootEntryVo> result = Lists.newArrayList();
        List<Long> userIds = bootEntryUserList.stream().map(BootEntryUserConfig::getId).collect(Collectors.toList());
        BoolQueryBuilder queryCountBuilder = QueryBuilders.boolQuery();
        queryCountBuilder.must(QueryBuilders.termsQuery("userRoleId",userIds));
        List<BootEntryConfig> bootEntryConfigs = bootEntryDao.getListByQuery(queryCountBuilder);
        Map<Long, List<BootEntryConfig>> bootEntryMap = bootEntryConfigs.stream().collect(Collectors.groupingBy(item -> item.getUserRoleId()));
        for (BootEntryUserConfig bootEntryUserConfig : bootEntryUserList) {
            List<BootEntryConfig> roleBootEntry = bootEntryMap.get(bootEntryUserConfig.getId());
            List<BootEntryConfig> filterBootEntry = roleBootEntry.stream().filter(item -> (item.getFunctionId().equals("menu_data") || moduleId.contains(Long.valueOf(item.getFunctionId())))).collect(Collectors.toList());
            if (filterBootEntry == null || filterBootEntry.size() < 1) {
                continue;
            }
            filterBootEntry.sort(Comparator.comparing(BootEntryConfig :: getSort));
            BootEntryVo bootEntryVo = new BootEntryVo();
            bootEntryVo.setUserName(bootEntryUserConfig.getUserName());
            bootEntryVo.setUserId(bootEntryUserConfig.getId());
            bootEntryVo.setIcon(bootEntryUserConfig.getIcon());
            bootEntryVo.setBootEntryConfigList(filterBootEntry);
            result.add(bootEntryVo);
        }
        return result;
    }

    @Override
    public int deleteBootEntry(Long bootEntryId,Long userRoleId) {
        BoolQueryBuilder queryCountBuilder = QueryBuilders.boolQuery();
        queryCountBuilder.must(QueryBuilders.termQuery("userRoleId",userRoleId));
        queryCountBuilder.must(QueryBuilders.termQuery("id",bootEntryId));
        Integer integer = bootEntryDao.deleteByQuery(queryCountBuilder, true);
        BootEntryConfig bootEntryConfig = new BootEntryConfig();
        bootEntryConfig.setUserRoleId(userRoleId);
        List<SortBuilder<?>> functionSort = new LinkedList<>();
        functionSort.add(SortBuilders.fieldSort("sort").order(SortOrder.ASC));
        List<BootEntryConfig> sortListByCdt = bootEntryDao.getSortListByCdt(bootEntryConfig, functionSort);
        for (int i=0; i<sortListByCdt.size(); i++) {
            sortListByCdt.get(i).setSort(i+1);
        }
        bootEntryDao.saveOrUpdateBatch(sortListByCdt);
        return integer;
    }

    @Override
    public Long saveBootPageProgress(BootPageProgress bootPageProgress) {
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        bootPageProgress.setUserId(loginCode);
        if (bootPageProgress.getRoleId() == null) {
            throw new BinaryException("当前进度的角色id不能空");
        }
        if (bootPageProgress.getBootEntryId() == null) {
            throw new BinaryException("当前完成的引导项id不能为空");
        }
        bootPageProgress.setId(ESUtil.getUUID());
        Long result = bootPageProgressDao.saveOrUpdate(bootPageProgress);
        return result;
    }

    @Override
    public Long saveBootTrialPageProgress(String bootTrialPageCode) {

        if(StringUtils.isBlank(bootTrialPageCode)){
            throw new BinaryException("试用向导页编码不能为空");
        }

        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("userId.keyword",loginCode));
        if(StringUtils.isNotBlank(bootTrialPageCode)){
            queryBuilder.must(QueryBuilders.termQuery("bootTrialPageCode.keyword",bootTrialPageCode));
        }
        List<BootTrialPageProgess> bootTrialPageProgessList = bootTrialPageProgressDao.getListByQueryScroll(queryBuilder);

        if (bootTrialPageProgessList != null && bootTrialPageProgessList.size() > 0) {
            return bootTrialPageProgessList.get(0).getId();
        }


        BootTrialPageProgess bootTrialPageProgess = new BootTrialPageProgess();
        bootTrialPageProgess.setId(ESUtil.getUUID());
        bootTrialPageProgess.setUserId(loginCode);
        bootTrialPageProgess.setBootTrialPageCode(bootTrialPageCode);

        Long result = bootTrialPageProgressDao.saveOrUpdate(bootTrialPageProgess);

        return result;
    }

    @Override
    public Boolean getUserBootTrialPageProcess(String bootTrialPageCode) {

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("userId.keyword",SysUtil.getCurrentUserInfo().getLoginCode()));
        if(StringUtils.isNotBlank(bootTrialPageCode)){
            queryBuilder.must(QueryBuilders.termQuery("bootTrialPageCode.keyword",bootTrialPageCode));
        }
        List<BootTrialPageProgess> bootTrialPageProgessList = bootTrialPageProgressDao.getListByQueryScroll(queryBuilder);

        if (bootTrialPageProgessList == null || bootTrialPageProgessList.size() < 1) {
            return false;
        }
        return true;
    }

    @Override
    public List<BootPageProgress> getUserRoleProgress(Long userRoleId) {
        List<BootEntryVo> bootEntryList = getBootEntryList();
        for (BootEntryVo bootEntryVo : bootEntryList) {
            if (userRoleId.equals(bootEntryVo.getUserId())) {
                List<BootEntryConfig> bootEntryConfigList = bootEntryVo.getBootEntryConfigList();
                Set<Long> progressIds = bootEntryConfigList.stream().map(BootEntryConfig::getId).collect(Collectors.toSet());
                BootPageProgress bootPageProgress = new BootPageProgress();
                bootPageProgress.setUserId(SysUtil.getCurrentUserInfo().getLoginCode());
                bootPageProgress.setRoleId(userRoleId);
                List<BootPageProgress> resultAll = bootPageProgressDao.getListByCdt(bootPageProgress);
                List<BootPageProgress> result = resultAll.stream().filter(item -> progressIds.contains(item.getBootEntryId())).collect(Collectors.toList());
                return result;
            }
        }

        return Lists.newArrayList();
    }

    @Override
    public Long addBootPageUser(BootEntryUserConfig bootEntryUserConfig) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (bootEntryUserConfig.getUserName() == null) {
            throw new BinaryException("添加的人员名称不能为空");
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("userName",bootEntryUserConfig.getUserName()));
        if (bootEntryUserConfig.getId() == null) {
            bootEntryUserConfig.setId(ESUtil.getUUID());
            bootEntryUserConfig.setDomainId(SysUtil.getCurrentUserInfo().getDomainId());
        }else{
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id",bootEntryUserConfig.getId()));
        }
        long count = bootEntryUserDao.countByCondition(boolQueryBuilder);
        if (count > 0) {
            throw new BinaryException("添加的人员名称重复");
        }
        return bootEntryUserDao.saveOrUpdate(bootEntryUserConfig);
    }

    @Override
    public List<BootEntryUserConfig> getBootPageUsers() {
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("sort").order(SortOrder.ASC));
        Page<BootEntryUserConfig> sortListByCdt = bootEntryUserDao.getSortListByCdt(1, 2000, new BootEntryUserConfig(), sorts);
        return sortListByCdt.getData();
    }

    @Override
    public ResponseEntity<byte[]> exportConfigInitData() {
        BootEntryUserConfig bootEntryUserConfig = new BootEntryUserConfig();
        bootEntryUserConfig.setIsFromStandard(true);
        List<BootEntryUserConfig> bootEntryUserConfigs = bootEntryUserDao.getListByCdt(bootEntryUserConfig);


        String configListString = JSON.toJSONString(bootEntryUserConfigs);

        File file = new File( bootEntryUserDao.getIndex() + ".json");
        try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
            IOUtils.write(configListString, fileOutputStream, String.valueOf(StandardCharsets.UTF_8));
        } catch (IOException e) {
            log.error("制品文件生成失败",e);
        }
        ResponseEntity<byte[]> responseEntity = returnRes(file);
        //FileUtils.deleteQuietly(file);
        return responseEntity;
    }

    @Override
    public ResponseEntity<byte[]> exportBootEntryInitData() {
        BootEntryConfig bootEntryConfig = new BootEntryConfig();
        bootEntryConfig.setIsFromStandard(true);
        List<BootEntryConfig> exportData = bootEntryDao.getListByCdt(bootEntryConfig);
        String configListString = JSON.toJSONString(exportData);

        File file = new File( bootEntryDao.getIndex() + ".json");
        try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
            IOUtils.write(configListString, fileOutputStream, String.valueOf(StandardCharsets.UTF_8));
        } catch (IOException e) {
            log.error("制品文件生成失败",e);
        }
        ResponseEntity<byte[]> responseEntity = returnRes(file);
        //FileUtils.deleteQuietly(file);
        return responseEntity;
    }

    @Override
    public  List<Long> getModuleById(Long moduleId) {
        CSysModule cSysModule = new CSysModule();
        cSysModule.setId(moduleId);
        List<SysModule> modulesByCdt = svc.getModulesByCdt(cSysModule);
        if (modulesByCdt == null || modulesByCdt.size() < 1) {
            return null;
        }
        List<Long> parentModuleIds = Lists.newArrayList();
        findParentModuleIds(modulesByCdt,parentModuleIds);
        Collections.reverse(parentModuleIds);
        return parentModuleIds;
    }

    public void findParentModuleIds(List<SysModule> modulesByCdt,List<Long> parentModuleIds) {
        if (modulesByCdt.get(0).getParentId() == 0l) {
            return;
        }
        parentModuleIds.add(modulesByCdt.get(0).getParentId());
        CSysModule cSysModule = new CSysModule();
        cSysModule.setId(modulesByCdt.get(0).getParentId() );
        List<SysModule> childList = svc.getModulesByCdt(cSysModule);
        findParentModuleIds(childList,parentModuleIds);
    }


    @Override
    public Boolean showButton() {
        BootPageProgress bootPageProgress= new BootPageProgress();
        bootPageProgress.setUserId(SysUtil.getCurrentUserInfo().getLoginCode());
        List<BootPageProgress> bootPageProgresses = bootPageProgressDao.getListByCdt(bootPageProgress);
        if (bootPageProgresses == null || bootPageProgresses.size() < 1) {
            return true;
        }
        return false;
    }

    @Override
    public Long updateRoleField() {
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        SysRole sysRole = roleSvc.getByName(domainId, "admin");
        sysRole.setBootEntryRoleIds(Arrays.asList(1l,2l,3l,4l,5l));
        Long result = roleSvc.saveOrUpdate(sysRole);
        return result;
    }

    @Override
    public void brushStockRoles() {
        CSysRole sysRole = new CSysRole();
        List<SysRole> allRoles = roleSvc.getListByCdt(sysRole);
        if (allRoles == null || allRoles.size() < 1) {
            return;
        }
        List<SysRole> filterData = allRoles.stream().filter(item -> item.getBootEntryRoleIds() == null || item.getBootEntryRoleIds().size() < 1).collect(Collectors.toList());
        for (SysRole filterDatum : filterData) {
            filterDatum.setBootEntryRoleIds(Arrays.asList(1l,2l,3l,4l,5l));
        }
        roleSvc.saveOrUpdateBatch(filterData);
    }

    private Long checkAndUpdateParameter(BootEntryBo bootEntryBo) {
        int flag = 0;
        String bootEntryName = bootEntryBo.getBootEntryName();
        Long userRoleId = bootEntryBo.getUserRoleId();
        if (userRoleId == null) {
            throw new BinaryException("引导项所属角色不能为空");
        }
        if (StringUtils.isNoneBlank(bootEntryName)) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termQuery("bootEntryName.keyword",bootEntryName));
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id",bootEntryBo.getId()));
            boolQueryBuilder.must(QueryBuilders.termQuery("userRoleId",userRoleId));
            long count = bootEntryDao.countByCondition(boolQueryBuilder);
            if (count > 0) {
                throw new BinaryException("引导项名称重复:"+bootEntryName);
            }
        }
        BootEntryConfig bootEntryConfig = EamUtil.copy(bootEntryBo, BootEntryConfig.class);
        bootEntryConfig.setModifyTime(ESUtil.getNumberDateTime());
        Long result = bootEntryDao.saveOrUpdate(bootEntryConfig);
        return result;

    }

    private Long checkAndSaveParameter(BootEntryBo bootEntryBo) {
        String bootEntryName = bootEntryBo.getBootEntryName();
        Long userRoleId = bootEntryBo.getUserRoleId();
        if (StringUtils.isBlank(bootEntryName)) {
            throw new BinaryException("引导项名称不能为空");
        }
        if (userRoleId == null) {
            throw new BinaryException("引导项所属角色不能为空");
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("bootEntryName.keyword",bootEntryName));
        boolQueryBuilder.must(QueryBuilders.termQuery("userRoleId",userRoleId));
        long count = bootEntryDao.countByCondition(boolQueryBuilder);
        if (count > 0) {
            throw new BinaryException("引导项名称重复:"+bootEntryName);
        }
        List<BootEntryFunctionConfig> bootEntryFunctionConfigList = bootEntryBo.getBootEntryFunctionConfigList();
        if (bootEntryFunctionConfigList == null || bootEntryFunctionConfigList.size() < 1) {
            throw new BinaryException("配置引导项菜单列表不能为空");
        }
        BootEntryConfig bootEntryConfig = EamUtil.copy(bootEntryBo, BootEntryConfig.class);
        long uuid = ESUtil.getUUID();
        bootEntryConfig.setId(uuid);
        bootEntryConfig.setCreateTime(ESUtil.getNumberDateTime());
        bootEntryConfig.setModifyTime(ESUtil.getNumberDateTime());
        BoolQueryBuilder queryCountBuilder = QueryBuilders.boolQuery();
        queryCountBuilder.must(QueryBuilders.termQuery("userRoleId",userRoleId));
        long sumCount = bootEntryDao.countByCondition(queryCountBuilder);
        bootEntryConfig.setSort((int) sumCount+1);
        Long result = bootEntryDao.saveOrUpdate(bootEntryConfig);
        for (int i = 0; i < bootEntryFunctionConfigList.size(); i++) {
            BootEntryFunctionConfig bootEntryFunctionConfig = bootEntryFunctionConfigList.get(i);
            bootEntryFunctionConfig.setId(ESUtil.getUUID());
            bootEntryFunctionConfig.setBootEntryId(uuid);
            bootEntryFunctionConfig.setCreateTime(ESUtil.getNumberDateTime());
            bootEntryFunctionConfig.setModifyTime(ESUtil.getNumberDateTime());
            bootEntryFunctionConfig.setSort(i+1);
        }
       bootEntryFunctionDao.saveOrUpdateBatch(bootEntryFunctionConfigList);
        return result;
    }

    private RoleAndBootEntryRoleBo getUserRoleIds() {
        RoleAndBootEntryRoleBo roleAndBootEntryRoleBo = new RoleAndBootEntryRoleBo();
        Set<Long> bootEntryRoleIdSet = Sets.newHashSet();
        Set<Long> userRoleIds = Sets.newHashSet();
        Set<SysRole> userRoles = Sets.newHashSet();
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        Long userId = SysUtil.getCurrentUserInfo().getId();
        CSysUser sysUser = new CSysUser();
        sysUser.setLoginCode(loginCode);
        UserInfo userInfoById = userSvc.getUserInfoById(userId);
        Set<SysRole> roles = userInfoById.getRoles();
        if (roles != null) {
            for (SysRole role : roles) {
                userRoleIds.add(role.getId());
                if (role.getBootEntryRoleIds() != null && role.getBootEntryRoleIds().size() >= 1) {
                    bootEntryRoleIdSet.addAll(role.getBootEntryRoleIds());
                }
            }
            userRoles.addAll(userInfoById.getRoles());
        }
        if (userRoleIds == null || userRoleIds.size() < 1) {
            return null;
        }
        roleAndBootEntryRoleBo.setUserRoleIds(userRoleIds);
        roleAndBootEntryRoleBo.setBootEntryRoleIdSet(bootEntryRoleIdSet);

        return roleAndBootEntryRoleBo;
    }

    private ResponseEntity<byte[]> returnRes(File file) {
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity = null;
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            byte[] bytes = new byte[in.available()];
            int read = in.read(bytes);
            if (read != in.available()) {
                log.info("这块不能直接判断个数,需要等待所有读取完才能比较");
            }
            headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            entity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
        } catch (Exception e) {
            throw new MessageException(e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return entity;
    }

}
